﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using QuailDb;
using System.Text;

namespace QuailDashboard.View.Web
{
    public partial class Chart : System.Web.UI.Page
    {
        public string PageTitle { get; set; }

        public string Environment { get { return Request.QueryString["env"]; }}
        public string LibraryName { get { return Request.QueryString["lib"]; } }
        public string FullTestName { get { return Request.QueryString["test"]; } }
        public string ClassName { get { return Request.QueryString["class"]; } }
        public string PageLoad { get { return Request.QueryString["pgload"]; } }
        public DateTime FromDate { get { return GetDateFromQs("from").GetValueOrDefault(DateTime.Today - new TimeSpan(10, 0, 0, 0)); } }
        public DateTime ToDate { get { return GetDateFromQs("to").GetValueOrDefault(DateTime.Today); } }
        public string PercentFailed
        {
            get
            {
                string result = string.Empty;

                try
                {
                    result = int.Parse(Request.QueryString["pctf"]).ToString();
                }
                catch
                {
                    result = "0";
                }

                return result;
            }
        }

        public string MetricsTable { get; set; }

        public string CurrentTab { get; set; }
        
        private DateTime? _startingDate, _endingDate;

        private DateTime? GetDateFromQs(string name)
        {
            var str = Request.QueryString[name];

            DateTime dt;
            if (DateTime.TryParse(str, out dt))
                return dt;

            return null;
        }

        public void WriteData()
        {
            using (var svc = new QuailDataService())
            {
                var items = svc.GetFailedTestPercentages(Environment, LibraryName, FullTestName, FromDate, ToDate);

                if (string.IsNullOrEmpty(FullTestName) && !string.IsNullOrEmpty(ClassName))
                {
                    items = items.Where(ftp => ftp.TestClassName.IndexOf(ClassName) == 0).ToList();
                }

                WriteByDate(items);
                WriteWorstOffenders(items);

                var metrics = svc.GetFailedTestPercentagesOverall(_startingDate, _endingDate);
                WriteMetrics(metrics);
            }
        }

        protected string GetLibraryNameSelectOptions()
        {
            using (var svc = new QuailDataService())
            {
                string result = "<option value=''" + (string.IsNullOrEmpty(LibraryName) ? " selected" : string.Empty) + ">All</option>";

                result += svc.GetLibraries()
                    .Select(lib => "<option value=\"" + HttpUtility.HtmlEncode(lib.LibraryName) + "\"" 
                        + (LibraryName == lib.LibraryName ? " selected" : string.Empty) + ">" 
                        + HttpUtility.HtmlEncode(lib.LibraryName) + "</option>")
                .JoinStrings("\n");

                return result;
            }
        }

        protected string GetEnvironmentSelectOptions()
        {
            using (var svc = new QuailDataService())
            {
                string result = svc.GetEnvironments()
                    .OrderBy(te => te.EnvironmentName)
                    .Select(te => "<option value=\"" + HttpUtility.HtmlEncode(te.EnvironmentName) + "\""
                        + (Environment == te.EnvironmentName ? " selected" : string.Empty)
                        + ">" + HttpUtility.HtmlEncode(te.EnvironmentName) + "</option>")
                .JoinStrings("\n");

                return result;
            }
        }

        private void WriteMetrics(List<ViewFailedTestPercentagesOverallResult> metrics)
        {
            if (!string.IsNullOrEmpty(PageLoad))
            {
                var mytitle = "Metrics [" + FromDate.ToString("MM/dd/yyyy") + " - " + ToDate.ToString("MM/dd/yyyy") +
                              "]";
                metrics =
                    metrics.Where(
                        m =>
                        m.EnvironmentName == Environment &&
                        m.FailedPct >= Convert.ToDecimal(PercentFailed)).ToList();

                if (!string.IsNullOrEmpty(LibraryName))
                    metrics = metrics.Where(m => m.LibraryName.Contains(LibraryName)).ToList();

                if (metrics.Count > 0)
                {
                    var results =
                        new StringBuilder(
                            "<table><tr><th>Failed pct</th><th>Total</th><th>Failed</th><th>Test</th><th>Project (Library)</th></tr>");

                    foreach (var metric in metrics)
                    {
                        results.Append(
                            string.Format("<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>",
                                          metric.FailedPct, metric.Total, metric.Failed, metric.FullTestName,
                                          metric.LibraryName));
                    }

                    results.Append("</table>");

                    MetricsTable = results.ToString();
                }
                else
                {
                    MetricsTable = "No results!";
                }
            }

        }

        private void WriteWorstOffenders(IEnumerable<ViewFailedTestPercentage> items)
        {

            var mytitle =
                _startingDate.HasValue && _endingDate.HasValue
                    ? "Worst offenders [" + _startingDate.Value.ToString("MM/dd/yyyy") + " - " +
                      _endingDate.Value.ToString("MM/dd/yyyy") + "]"
                    : "Worst Offenders";

            var groups = items.GroupBy(item => item.TestName)
                .Select(bytest =>
                        new
                            {
                                TestName = bytest.Key,
                                Passed = bytest.Sum(t => t.Passed),
                                Fail = bytest.Sum(t => t.Failed),
                                FailEnv = bytest.Sum(t => t.FailedEnvironment)
                            })
                .Select(eachtest =>
                        new
                            {
                                eachtest.TestName,
                                eachtest.Passed,
                                Fail = eachtest.Fail - eachtest.FailEnv,
                                eachtest.FailEnv,
                                FailPct = eachtest.Fail == 0
                                              ? 0.0
                                              : (eachtest.Fail*1.0)/((eachtest.Passed + eachtest.Fail)*1.0)
                            })
                .OrderByDescending(eachtest => eachtest.FailPct)
                .Take(10)
                .ToList();

            Response.Write("{");
            Response.Write("var data = new google.visualization.DataTable();");
            Response.Write("data.addColumn('string','Test');");
            Response.Write("data.addColumn('number','Fail Environmental');");
            Response.Write("data.addColumn('number','Fail Other');");
            Response.Write("data.addColumn('number','Pass');");

            Response.Write("data.addRows([");

            var rowcount = groups.Count();
            var currentrow = 0;

            groups
                .ForEach(
                    data =>
                        {
                            currentrow++;

                            var pass = data.Passed;

                            var failenv = data.FailEnv;

                            var fail = data.Fail;

                            var IsLastRow = currentrow == rowcount;

                            var rowmask = (IsLastRow) ? "['{0}', {1}, {2}, {3}]" : "['{0}', {1}, {2}, {3}],"; // Exclude comma seperator on last row

                            Response.Write(string.Format(rowmask,
                                                         data.TestName,
                                                         failenv,
                                                         fail,
                                                         pass));
                    });

            Response.Write("]);");

            Response.Write(String.Format("var div = document.getElementById('chart{0}_div');", 2));

            string stuff = string.Empty;
            Func<string, string> append = (s) => stuff.Length == 0 ? s : (stuff + ", " + s);

            if (!string.IsNullOrEmpty(Environment))
                stuff = append(Environment);

            if (!string.IsNullOrEmpty(FullTestName))
                stuff = append(FullTestName);
            else
            {
                if (!string.IsNullOrEmpty(LibraryName))
                    stuff = append(LibraryName);
                if (!string.IsNullOrEmpty(ClassName))
                    stuff = append(ClassName);
            }

            Response.Write("var chart = new google.visualization.ColumnChart(div);");
            Response.Write(
                String.Format(
                    "chart.draw(data, {{ width: 1024, height: 500, title: '{0}', isStacked : true, series: [{{color:'orange'}},{{color:'red'}},{{color:'green'}}], " +
                    "hAxis: {{title: '{1}'}} }});",
                    mytitle, stuff));
            Response.Write("}");            
        }

        private void WriteByDate(IEnumerable<ViewFailedTestPercentage> items)
        {
            var groups = items.GroupBy(item => item.TestDate)
                .OrderByDescending(grp => grp.Key)
                .Take(30)
                .OrderBy(grp => grp.Key)
                .ToList();

            if (groups.Any())
            {
                _startingDate = groups.Min(g => g.Key).Value;
                _endingDate = groups.Max(g => g.Key).Value;

                PageTitle = "Test Results [" + _startingDate.Value.ToString("MM/dd/yyyy") + " - " +
                            _endingDate.Value.ToString("MM/dd/yyyy") + "]";
            }
            else
            {
                PageTitle = "Test Results";
            }

            Response.Write("{");
            Response.Write("var data = new google.visualization.DataTable();");
            Response.Write("data.addColumn('string','Date');");
            Response.Write("data.addColumn('number','Fail Environmental');");
            Response.Write("data.addColumn('number','Fail Other');");
            Response.Write("data.addColumn('number','Pass');");

            Response.Write("data.addRows([");

            var rowcount = groups.Count();
            var currentrow = 0;

            groups
                .ForEach(
                    data =>
                        {
                            currentrow++;
                            var pass = data
                                .Sum(ftp => ftp.Passed.Value);

                            var failenv = data
                                .Sum(ftp => ftp.FailedEnvironment.Value);

                            var fail = data
                                .Sum(ftp => ftp.Failed.Value) - failenv;

                            var IsLastRow = currentrow == rowcount;

                            var rowmask = (IsLastRow) ? "['{0}', {1}, {2}, {3}]" : "['{0}', {1}, {2}, {3}],"; // Exclude comma seperator on last row

                            Response.Write(string.Format(rowmask,
                                                     data.Key.Value.ToString("MMM d"),
                                                     failenv,
                                                     fail,
                                                     pass));
                    });

            Response.Write("]);");

            Response.Write(String.Format("var div = document.getElementById('chart{0}_div');", 1));

            string stuff = string.Empty;
            Func<string, string> append = (s) => stuff.Length == 0 ? s : (stuff + ", " + s);

            if (!string.IsNullOrEmpty(Environment))
                stuff = append(Environment);

            if (!string.IsNullOrEmpty(FullTestName))
                stuff = append(FullTestName);
            else
            {
                if (!string.IsNullOrEmpty(LibraryName))
                    stuff = append(LibraryName);
                if (!string.IsNullOrEmpty(ClassName))
                    stuff = append(ClassName);
            }

            Response.Write("var chart = new google.visualization.ColumnChart(div);");
            Response.Write(
                String.Format(
                    "chart.draw(data, {{ width: 1024, height: 500, title: '{0}', isStacked : true, series: [{{color:'orange'}},{{color:'red'}},{{color:'green'}}], " +
                    "hAxis: {{title: '{1}'}} }});",
                    PageTitle, stuff));
            Response.Write("}");
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            // Setting CurrentTab will print out jQuery to select the current tab based on the PageLoad hidden var from the submitted form
            CurrentTab = string.Format("$('#tabs').tabs('select', {0});", string.IsNullOrEmpty(PageLoad) ? "0" : PageLoad);
        }
    }
}